﻿using System;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using Catel.Articles._03___MVVM.Properties;
using Catel.Data;

namespace Catel.Articles._03___MVVM.Models
{
    using System.Collections.Generic;

    #region Enums
    /// <summary>
    /// Gender of a person.
    /// </summary>
    public enum Gender
    {
        /// <summary>
        /// Unknown.
        /// </summary>
        Unknown,

        /// <summary>
        /// Male.
        /// </summary>
        Male,

        /// <summary>
        /// Female.
        /// </summary>
        Female
    }
    #endregion

    /// <summary>
    /// Person Data object class which fully supports serialization, property changed notifications,
    /// backwards compatibility and error checking.
    /// </summary>
    [Serializable]
    public class Person : DataObjectBase<Person>
    {
        #region Variables
        #endregion

        #region Constructor & destructor
        /// <summary>
        /// Initializes a new object from scratch.
        /// </summary>
        public Person()
        {
            // Create collection
            PersonCollection = new ObservableCollection<Person>();
        }

        /// <summary>
        /// Initializes a new object based on <see cref="SerializationInfo"/>.
        /// </summary>
        /// <param name="info"><see cref="SerializationInfo"/> that contains the information.</param>
        /// <param name="context"><see cref="StreamingContext"/>.</param>
        protected Person(SerializationInfo info, StreamingContext context)
            : base(info, context) { }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the first name.
        /// </summary>
        public string FirstName
        {
            get { return GetValue<string>(FirstNameProperty); }
            set { SetValue(FirstNameProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData FirstNameProperty = RegisterProperty("FirstName", typeof(string), string.Empty, 
            (sender, e) => ((Person)sender).UpdateFullName());

        /// <summary>
        /// Gets or sets the middle name.
        /// </summary>
        public string MiddleName
        {
            get { return GetValue<string>(MiddleNameProperty); }
            set { SetValue(MiddleNameProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData MiddleNameProperty = RegisterProperty("MiddleName", typeof(string), string.Empty, 
            (sender, e) => ((Person)sender).UpdateFullName());

        /// <summary>
        /// Gets or sets the last name.
        /// </summary>
        public string LastName
        {
            get { return GetValue<string>(LastNameProperty); }
            set { SetValue(LastNameProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData LastNameProperty = RegisterProperty("LastName", typeof(string), string.Empty, 
            (sender, e) => ((Person)sender).UpdateFullName());

        /// <summary>
        /// Gets the full name.
        /// </summary>
        /// <value>The full name.</value>
        public string FullName
        {
            get { return string.Format("{0} {1} {2}", FirstName, MiddleName, LastName); }
        }

        /// <summary>
        /// Gets or sets the gender.
        /// </summary>
        public Gender Gender
        {
            get { return GetValue<Gender>(GenderProperty); }
            set { SetValue(GenderProperty, value); }
        }

        /// <summary>
        /// Register the property so it is known in the class.
        /// </summary>
        public readonly PropertyData GenderProperty = RegisterProperty("Gender", typeof(Gender), Gender.Unknown);

        /// <summary>
        /// Gets or sets the employees.
        /// </summary>
        public ObservableCollection<Person> PersonCollection
        {
            get { return GetValue<ObservableCollection<Person>>(PersonCollectionProperty); }
            set { SetValue(PersonCollectionProperty, value); }
        }

        /// <summary>
        /// Register the PersonCollection property so it is known in the class.
        /// </summary>
        public static readonly PropertyData PersonCollectionProperty = RegisterProperty("PersonCollection", typeof(ObservableCollection<Person>));
        #endregion

        #region Methods
        protected override void ValidateFields(List<FieldValidationResult> validationResults)
        {
            if (string.IsNullOrEmpty(FirstName))
            {
                validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty, Resources.ErrorPersonFirstNameRequired));
            }

            if (string.IsNullOrEmpty(LastName))
            {
                validationResults.Add(FieldValidationResult.CreateError(LastNameProperty, Resources.ErrorPersonLastNameRequired));
            }

            if (Gender == Gender.Unknown)
            {
                validationResults.Add(FieldValidationResult.CreateError(GenderProperty, Resources.ErrorPersonGenderCannotBeUnknown));
            }
        }

        /// <summary>
        /// Updates the full name.
        /// </summary>
        private void UpdateFullName()
        {
            RaisePropertyChanged(() => FullName);
        }
        #endregion
    }
}
